package org.walklink.common.util;

import org.walklink.common.common.AbstractLazyInitializer;
import org.walklink.common.entity.jvm.JvmGcInfoDto;
import org.walklink.common.entity.jvm.JvmMemoryInfoDto;
import org.walklink.common.entity.jvm.JvmTrackDto;

import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * JVM栈信息输出
 *
 * @author lidishan
 */
public class JvmStackUtil {

    /** 懒加载JVM信息 **/
    private static final AbstractLazyInitializer<JvmTrackDto> LAZY_JVM_INFO = new AbstractLazyInitializer<JvmTrackDto>() {
        @Override
        protected JvmTrackDto initialize() {
            return new JvmTrackDto()
                    .setJvmMemoryInfo(getMemoryInfo())
                    .setJvmGcInfo(getGcInfo());
        }
    };

    /**
     * 获取所有JVM信息
     *
     * @return jvm信息
     */
    public static JvmTrackDto getAllJvmInfo() {
        return LAZY_JVM_INFO.get();
    }

    /**
     * 获取内存信息
     *
     * @return 内存信息
     */
    public static JvmMemoryInfoDto getMemoryInfo() {
        MemoryMXBean memory = ManagementFactory.getMemoryMXBean();

        // 填充堆、非堆
        MemoryUsage headMemory = memory.getHeapMemoryUsage();
        MemoryUsage nonHeadMemory = memory.getNonHeapMemoryUsage();

        return (new JvmMemoryInfoDto())
                // 堆部分
                .setHeadInitMemory(headMemory.getInit())
                .setHeadMaxMemory(headMemory.getMax())
                .setHeadCommittedMemory(headMemory.getCommitted())
                .setHeadUsedMemory(headMemory.getUsed())
                // 非堆部分
                .setNoHeadInitMemory(nonHeadMemory.getInit())
                .setNoHeadMaxMemory(nonHeadMemory.getMax())
                .setNoHeadCommittedMemory(nonHeadMemory.getCommitted())
                .setNoHeadUsedMemory(nonHeadMemory.getUsed());
    }

    /**
     * 获取GC信息
     *
     * @return GC信息
     */
    public static List<JvmGcInfoDto> getGcInfo() {
        List<GarbageCollectorMXBean> garbages = ManagementFactory.getGarbageCollectorMXBeans();
        List<JvmGcInfoDto> result = new ArrayList<>();
        for (GarbageCollectorMXBean garbage : garbages) {
            result.add(
                    (new JvmGcInfoDto())
                            .setName(garbage.getName())
                            .setCount(garbage.getCollectionCount())
                            .setCollectionTime(garbage.getCollectionTime())
                            .setPoolName(Arrays.deepToString(garbage.getMemoryPoolNames()))
            );
        }
        return result;
    }

}